Products Shop Support Company |
Change Logs.

Oxygene Language Features

This page describes the major new language features provided by Oxygene, grouped by the release when they were introduced.

 

New Language Features in Oxygene 3.0

 

Parallel Programming

Oxygene 3.0 introduces a wide range of language concepts that push the envelope for parallel programming and enable developers to create applications that seamlessly scale up for multi-core and many-core systems. This includes support for Futures, Parallel Loops, Asynchronous Statements, an improved locked directive, and more.

Property Notifications

Native language support for property notifications makes it easy to develop solutions that follow the Model/View/Controller design pattern or generally react in well-defined ways to property changes.

Nullable Expressions

Oxygene's Expression syntax has been expanded to provide full support for nullable types in arithmetic and other expressions, making the language integration of nullables even more seamless than in 'Joyride'. Improvements have also been made for casting between compatible nullable types, such as assigning a nullbale Int32 to a nullable Int64, etc.

Improved QA Analysis Tools

Improvements have been made to Oxygene to provide better feedback on quality of code, including new Code Flow Analysis and FxCop Code Analysis options integrated with the compiler, and the option to enforce proper case when using identifiers.

 

New Language Features in Version 2.0 ('Joyride')

 

Sequences and Query Expressions

Query Expressions, also known as "Language Integrated Query", or LINQ for short, are a powerful new language feature that allows you to combine the querying capabilities of database languages such as SQL and apply it to any type of data, natively within the Oxygene language.

Queries can be written to work on any type of structured collection, from simple lists and arrays to database tables and other data structures. Combined with the DLinq and XLinq libraries provided by Microsoft as part of the .NET 3.5 runtime, the feature can be used to efficiently query data from database sources and XML documents, without actually retrieving the entire set of data into memory. (Read more in CLG09)

var u := from u in lUsers where u.Age = 35 order by u.Name;

Lambda Expressions

Mostly used alongside LINQ and query support, lambda expressions provide a unique syntax for passing dynamic expressions as part of method parameters. (CLG09)

var lFiltered := lUsers.Where(u -> u.Age = 35);

Anonymous Types

Once again mostly used in LINQ expressions, anonymous types allow you quickly declare unnamed classes within a method body, to group related values in a common entity.

var lUser := new class(Name := 'Peter', Age := 49); Console.WriteLine(lUser.Name+' is '+lUser.Age+' years old');

Partial Methods New in 2.0.3

New Partial Method support allows you to define a stub for a method in one part of a class, allowing an optional implementation to be provided by another partial. If no implementation is provided, the method and any calls to it will be omitted from the generated assembly.

Partial Methods make it easy for auto-generated code to define methods that can be implemented by the user. This is used extensively in our new Cocoa# support, as well as upcoming support for LINQ to SQL.

Enhanced Nullable Types

'Joyride' enhanced support for nullable types, making them a full language feature that fits in neatly with the other types rather than having nullable types feel like a runtime trick. For example, variables defined as nullable Int32 allow full access to members of Int32 and behave like a true Int32 in every sense - with the addition of allowing nil values.

In combination with the new ":" operator (described below) and the newly introduced ValueOrDefault() helper function, nullable types are now easier to use than ever, and feel more natural than in any other .NET language.

Extension Methods

Extension methods are a feature introduced by Microsoft in the .NET 3.5 runtime to support LINQ, but can be used in Oxygene in a wide variety of scenarios and on all framework versions.

Simply put, Extension Methods are methods declared in a static class that extend an existing class or interface, and can be invoked on a variable of that type. For example the Where extension method provided by .NET 3.5 extends IEnumerable, and thus can be used on any sequence of objects to filter the collection on an arbitrary condition, even though IEnumerable does not provide a Where member:

var lUsers := array of User; //... var lPauls := lUsers.Where(u -> u.Name = 'Paul');

Anonymous Methods

Anonymous methods make it possible to specify code assigned to event handlers or passed to delegates right within the body of another method. They not only allow you to skip manually declaring a method within the class, but they also seamlessly allow access to any local variables available within the context where the anonymous method is written.

method SetEventHandler; begin var lNewCaption := 'Clicked!'; Button1.Click += method(Sender: Object; ea: EventArgs); begin Button1.Text := lNewCaption MessageBox.Show('the button was clicked.'); end; end;

Colon ':' Operator

'Joyride' introduces a new operator that can be used anyplace the familiar "." can is used, be it to access a method, properties or other members of a type. Different from the "." operator, which requires the value on its left to be assigned (and will usually throw a NullReferenceException if it is not), the new ":" operator will allow to call members on any value, including nil. If the expression on the left of the colon is nil, the entire expression will automatically short-circuit to return nil as well.

This makes it very easy to access nested members in object hierarchies, when multiple if assigned() checks would otherwise be needed. (BLOG)

var lGreatGrandDadsName := lUser:Parent:Parent:Parent:Name;

'Params' Keyword

The params keyword makes it easy to define methods that take a variable number of arguments. By closing the list of parameters with an array parameter prefixed with the params keyword, you can enable callers of your method to pass variable numbers of elements to method calls, which will automatically be converted into an array. This makes it easier to call the method, especially from languages like C#, where constructing an inline array is long and unwieldy.

method Format(aFormat: string: params values: array of Int32); //... Format('...', 1, 2, 3, 5, 27);

'implies' Operator

The new implies operator was designed specifically for require/ensure clauses and class invariants, but can also be used elsewhere in code. Similar to and and or, it combines two boolean expressions; the difference is that with implies, the second expression is only evaluated if the first/left expression is true. if the first expression is false, the entire expression will be considered true.

ensure HasDriversLicense implies Age >= 16;

Type Inference for 'for each' Loops on Generic Sequences

For 'Joyride', for each loops have been improved to automatically infer the type of the loop variable when working on a generic IEnumerable or other strongly-typed sequence, avoiding the need to manually specify the type name. As a side effect, for each loops will now always implicitly define their loop variable.

var lUsers: array of Users; for each u in Users do Console.WriteLine(u.Name); // Compiler knows "u" is a "User"

For non-generic enumerations (IEnumerable), a explicit type declaration will be required inside the for each loop; the compiler will not automatically infer to use System.Object.

'index' Operator for 'for each' Loops

The Syntax for for each loops has been expanded in 'Joyride' to allow for an optional index variable to be defined, which will count from 0 through the number of elements looped. This is helpful in scenarios where the number of elements processed is needed as part of the loop, be it to access a separate collection by index, or to use different code to handle the first or even/odd elements.

When using for each matching or other mechanisms (such as LINQ) to filter down the collection, the index will only count those elements that actually execute the loop.

for each u in Users index i do begin if i > 0 then Console.Write(';'); Console.Write(u.Name); end;

 

 

New Language Features in Version 1.5 ('Floorshow')

 

Generic Methods

Use Generics to implement strongly typed methods with and parameterized types (.NET 2.0 only). (Read more on Generics in CH03)

Iterators

Easily implement collections and enumerable classes using iterators for both .NET 1.1 and 2.0 using the new 'iterator' directive and the 'yield' keyword. (Read more in CLG09)

method CountTo100: Int32; iterator; begin for i: Int32 := 0 to 100 do yield i; end;

Nullable Types

Avoid boxing by using new nullable value types on the .NET 2.0 framework. Support for nullable types has been vastly enhanced for 'Joyride' (see above).

var i := nullable Int32; if assigned(i) then i.CompareTo(5);

Nested Types

Define and implement nested types using Oxygene's new and intuitive 'nested in' syntax

type HelperClass nested in MainClass = class //...

Dual-visibility for Properties

Define properties with different visibility levels for getter and setter, for example allowing public reading and protected writing of properties:

property Count: Int32 read fCount protected write SetCount;

Extended Constructor Calls

Create objects and initialize properties in a single statement

var b := new Button(Width := 150; Height := 25);

Fixed Size Buffers

Use Fixed Size Buffers to declare efficient inline arrays inside your records, in "unsafe" code.

 

 

New Language Features in Version 1.0

The first version of Oxygene added the following language features on top of traditional Object Pascal implementations such as Delphi and Free Pascal:

Generic Types

Use Generics to implement strongly typed containers and parameterized types (.NET 2.0 only). (Read more on Generics in CH03)

Class Contracts

Oxygene is the first mainstream .NET language to provide native support for Design By Contract like constructs, with pre-conditions, post-conditions and invariants.

Namespace Support

Namespaces are one of the great basic concepts of the .NET framework that most developers take for granted. Oxygene provides three basic features that allow developers to work with namespaces.

Virtual Properties

Virtual Properties and Events allow you to more easily define abstract classes and interfaces, or overwrite existing framework interfaces that contain properties.

Enhanced Events Support

Oxygene introduces a new syntax for defining and working with events to the Object Pascal language.

Asynchronous Methods and Thread Synchronization

Easily write multi-threaded applications using Oxygenes' async keyword and asynchronous methods. Use the locked and locking keywords to write thread-safe applications.

Partial Classes

The only .NET compiler to provide partial classes support for .NET 1.1.

Operator Overloading

Make your classes intuitive to use by providing custom operator overloads for common operations such as addition or subtraction.

Class References & Virtual Constructors

Easily implement the Factory Pattern or dynamically create object instances using Oxygene's Class References (Meta Classes).

Enhanced Loops

Oxygene enhances the classic for/to loop to allow inline declaration of the loop variable type. It also provides a new for each loop type for looping across .NET IEnumerable and IEnumerable types, as well as an infinite loop loop.

Inline Variable Declarations and Type Inference

Declare new variables using the 'var' statement inside your method bodies to keep them with the code that uses them. Avoid retyping type names and let Oxygene infer new variable types from the assigned value.

Inline Property Readers

Use inline code to implement simple property readers, such as

property Foo: String read 'Bar';

Enhanced 'case of' and 'case type of' statements

Write 'case' statements using strings or other non-ordinal types, and use the new 'case type of' statement to execute different cases depending of an object's type.

Enhanced 'try/finally/except'

Combine 'finally' and 'except' to create more concise and efficient exception handling code.

Exception Filters

Previously only available in Visual Basic .NET, Exception Filters provide extended flexibility for catching exceptions over common 'try/except' blocks.

Boolean Double Comparisons

Easily compare values against boundaries with statements such as

if 0 if 0 <= x if 0 <= x < Count then //...

Empty Methods

Quickly define class interfaces to flesh out later or empty methods to be overridden in descendant classes.

Static Classes

Implement static classes that cannot be instantiated at runtime, but provide static functionality to your project.

Enhanced 'exit' statement

Use the improved exit statement to terminate methods and set a return value in a single step.

Enhanced 'is not' and 'not in' statements

Use the new 'is not' operator to write more readable type check statements, and 'not in' for improved set handling.